package com.tnovoselec.android.lbs.map;

import java.util.List;

import android.graphics.drawable.Drawable;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.view.ViewGroup.LayoutParams;

import com.google.android.maps.GeoPoint;
import com.google.android.maps.ItemizedOverlay;
import com.google.android.maps.MapController;
import com.google.android.maps.MapView;
import com.google.android.maps.Overlay;
import com.google.android.maps.OverlayItem;
import com.tnovoselec.android.lbs.R;

public abstract class BalloonOverlay<E extends OverlayItem> extends ItemizedOverlay<E> {

	private final MapView mapView;
	private final MapController mapController;

	private BalloonView<E> balloonView = null;
	private View clickRegion = null;
	private int viewOffset = 0;

	protected E currentFocussedItem = null;
	protected int currentFocussedIndex = 0;

	// TODO Put resources and layouts in constructors also!
	public BalloonOverlay(Drawable defaultMarker, MapView mapView) {
		super(defaultMarker);
		this.mapView = mapView;
		mapController = mapView.getController();
	}

	public int getBalloonBottomOffset() {
		return viewOffset;
	}

	public void setBalloonBottomOffset(int pixels) {
		viewOffset = pixels;
	}

	protected abstract boolean onBalloonTap(int index, E item);

	@Override
	protected boolean onTap(int index) {
		currentFocussedIndex = index;
		currentFocussedItem = createItem(index);

		boolean isRecycled = false;
		if (balloonView == null) {
			balloonView = createBalloonOverlayView();
			clickRegion = balloonView.findViewById(R.id.balloon_inner_layout);
			clickRegion.setOnTouchListener(createBalloonTouchListener());
		} else {
			isRecycled = true;
		}

		balloonView.setVisibility(View.GONE);

		List<Overlay> mapOverlays = mapView.getOverlays();
		if (mapOverlays.size() > 1) {
			hideOtherBalloons(mapOverlays);
		}

		balloonView.setData(currentFocussedItem);

		GeoPoint point = currentFocussedItem.getPoint();
		MapView.LayoutParams params = new MapView.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT, point, MapView.LayoutParams.BOTTOM_CENTER);
		params.mode = MapView.LayoutParams.MODE_MAP;

		balloonView.setVisibility(View.VISIBLE);

		if (isRecycled) {
			balloonView.setLayoutParams(params);
		} else {
			mapView.addView(balloonView, params);
		}

		mapController.animateTo(point);
		return true;
	}

	/**
	 * Creates the balloon view. Override to create a sub-classed view that
	 * can populate additional sub-views.
	 */
	protected BalloonView<E> createBalloonOverlayView() {
		return new BalloonView<E>(getMapView().getContext(), getBalloonBottomOffset());
	}

	protected MapView getMapView() {
		return mapView;
	}

	protected void hideBalloon() {
		if (balloonView != null) {
			balloonView.setVisibility(View.GONE);
		}
	}

	private void hideOtherBalloons(List<Overlay> overlays) {
		for (Overlay overlay : overlays) {
			if ((overlay instanceof BalloonOverlay<?>) && (overlay != this)) {
				((BalloonOverlay<?>) overlay).hideBalloon();
			}
		}
	}

	private OnTouchListener createBalloonTouchListener() {
		return new OnTouchListener() {

			@Override
			public boolean onTouch(View v, MotionEvent event) {
				View l = ((View) v.getParent()).findViewById(R.id.balloon_main_layout);
				Drawable d = l.getBackground();

				switch (event.getAction()) {
					case MotionEvent.ACTION_DOWN:
						int[] states = { android.R.attr.state_pressed };
						if (d.setState(states)) {
							d.invalidateSelf();
						}

						return true;
					case MotionEvent.ACTION_UP:
						int newStates[] = {};
						if (d.setState(newStates)) {
							d.invalidateSelf();
						}

						onBalloonTap(currentFocussedIndex, currentFocussedItem);
						return true;
					default:
						return false;
				}
			}
		};
	}
}
